﻿#include "AstDll.h"

#include <QLibrary>

#include "AstScene.h"
#include "AstStruct.h"

typedef int  (*__createInstance)(void**);
typedef void (*__freeInstance)(void*);

class AstDll::AstDllPrivate :public QObject
{
public:
	QLibrary*lib;

	__createInstance  create_instance;
	__freeInstance  free_instance;

	AstStruct * ast_struct;
public:
	AstDllPrivate(QObject*parent):QObject(parent)
	{
		lib = nullptr;
		create_instance = nullptr;
		free_instance = nullptr;
		ast_struct = nullptr;
	}
	~AstDllPrivate()
	{
		//unload(false);
	}
	void unload(bool free_enable)
	{
		if (lib) {
			lib->unload();

			if (free_instance) {
				if (ast_struct)
					free_instance(ast_struct);
			}
			if (free_enable)
				delete lib;
		}
		create_instance = nullptr;
		free_instance = nullptr;
		ast_struct = nullptr;
		lib = nullptr;
	}
	bool load(const QString&filename, QString*msg)
	{
		unload(true);

		lib = new QLibrary(filename, this);
		if (!lib->load()) {
			if (msg) *msg = lib->errorString();

			delete lib;
			return false;
		}

		create_instance = (__createInstance)lib->resolve("createInstance");
		free_instance = (__freeInstance)lib->resolve("freeInstance");

		create_instance((void**)&ast_struct);

		return true;
	}
};
AstDll::AstDll(QObject *parent)
	: QObject(parent), private_ptr(new AstDllPrivate(this))
{
}

AstDll::~AstDll()
{
}

bool AstDll::load(const QString&filename)
{
	return private_ptr->load(filename, nullptr);
}

AstStruct* AstDll::astStruct()
{
	return private_ptr->ast_struct;
}


/////////////////////////////////////////////////////////////////////////////
//
class AstDllGroup::AstDllGroupPrivate : public QObject
{
public:
	AstDllGroupPrivate(QObject*parent):QObject(parent)
	{}
};

AstDllGroup::AstDllGroup(QObject*parent): KGroupPtrT<QString, AstDll>(parent),private_ptr(new AstDllGroupPrivate(this))
{}

AstDll* AstDllGroup::load(const QString&filename)
{
	AstDll* dll = item(filename);

	if (dll)
		return dll;

	dll = new AstDll(this);

	if (!dll->load(filename)) {
		delete dll;
		return nullptr;
	}

	setItem(filename, dll);

	return dll;
}

QString AstDllGroup::sceneNames(int scene_type)
{
	QString s;
	QStringList lst;
	for each(auto a in *items()) {
		s = a->astStruct()->sceneNames(scene_type);
		if (!s.isEmpty()) {
			lst.append(s.split(","));
		}
	}
	return lst.join(",");
}

AstStruct* AstDllGroup::astStruct(const QString&name, int scene_type)
{
	for each(auto a in *items()) {
		if (a->astStruct()->hasScene(name, scene_type)) {
			return a->astStruct();
		}
	}
	return nullptr;
}
